{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#  两层FC层做分类：MNIST\n",
    "refer: http://wiki.jikexueyuan.com/project/tensorflow-zh/tutorials/mnist_beginners.html<br/>\n",
    "@author: huangyongye\n",
    "<br/>@date: 2017-02-24\n",
    "<br/><br/>在本教程中，我们来实现一个非常简单的两层全连接层来完成MNIST数据的分类问题。\n",
    "<br/>输入[-1,28*28], FC1 有 1024 个neurons， FC2 有 10 个neurons。这么简单的一个全连接网络，结果测试准确率达到了 0.98。还是非常棒的！！！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "\n",
    "# 设置按需使用GPU\n",
    "config = tf.ConfigProto()\n",
    "config.gpu_options.allow_growth = True\n",
    "sess = tf.InteractiveSession(config=config)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.导入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting MNIST_data/train-images-idx3-ubyte.gz\n",
      "Extracting MNIST_data/train-labels-idx1-ubyte.gz\n",
      "Extracting MNIST_data/t10k-images-idx3-ubyte.gz\n",
      "Extracting MNIST_data/t10k-labels-idx1-ubyte.gz\n"
     ]
    }
   ],
   "source": [
    "# 用tensorflow 导入数据\n",
    "from tensorflow.examples.tutorials.mnist import input_data\n",
    "mnist = input_data.read_data_sets('MNIST_data', one_hot=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "training data shape  (55000, 784)\n",
      "training label shape  (55000, 10)\n"
     ]
    }
   ],
   "source": [
    "print 'training data shape ', mnist.train.images.shape\n",
    "print 'training label shape ', mnist.train.labels.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 构建网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 权值初始化\n",
    "def weight_variable(shape):\n",
    "    # 用正态分布来初始化权值\n",
    "    initial = tf.truncated_normal(shape, stddev=0.1)\n",
    "    return tf.Variable(initial)\n",
    "\n",
    "def bias_variable(shape):\n",
    "    # 本例中用relu激活函数，所以用一个很小的正偏置较好\n",
    "    initial = tf.constant(0.1, shape=shape)\n",
    "    return tf.Variable(initial)\n",
    "\n",
    "\n",
    "# input_layer\n",
    "X_ = tf.placeholder(tf.float32, [None, 784])\n",
    "y_ = tf.placeholder(tf.float32, [None, 10])\n",
    "\n",
    "# FC1\n",
    "W_fc1 = weight_variable([784, 1024])\n",
    "b_fc1 = bias_variable([1024])\n",
    "h_fc1 = tf.nn.relu(tf.matmul(X_, W_fc1) + b_fc1)\n",
    "\n",
    "# FC2\n",
    "W_fc2 = weight_variable([1024, 10])\n",
    "b_fc2 = bias_variable([10])\n",
    "y_pre = tf.nn.softmax(tf.matmul(h_fc1, W_fc2) + b_fc2)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.训练和评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step 200, training acc 0.937364\n",
      "step 400, training acc 0.965818\n",
      "step 600, training acc 0.973364\n",
      "step 800, training acc 0.977709\n",
      "step 1000, training acc 0.981528\n",
      "= = = = = = = = = =  step 1000, testing acc 0.9688\n",
      "step 1200, training acc 0.988437\n",
      "step 1400, training acc 0.988728\n",
      "step 1600, training acc 0.987491\n",
      "step 1800, training acc 0.993873\n",
      "step 2000, training acc 0.992527\n",
      "= = = = = = = = = =  step 2000, testing acc 0.9789\n",
      "step 2200, training acc 0.995309\n",
      "step 2400, training acc 0.995455\n",
      "step 2600, training acc 0.9952\n",
      "step 2800, training acc 0.996073\n",
      "step 3000, training acc 0.9964\n",
      "= = = = = = = = = =  step 3000, testing acc 0.9778\n",
      "step 3200, training acc 0.996709\n",
      "step 3400, training acc 0.998109\n",
      "step 3600, training acc 0.997455\n",
      "step 3800, training acc 0.995055\n",
      "step 4000, training acc 0.997291\n",
      "= = = = = = = = = =  step 4000, testing acc 0.9808\n",
      "step 4200, training acc 0.997746\n",
      "step 4400, training acc 0.996073\n",
      "step 4600, training acc 0.998564\n",
      "step 4800, training acc 0.997946\n",
      "step 5000, training acc 0.998673\n",
      "= = = = = = = = = =  step 5000, testing acc 0.98\n"
     ]
    }
   ],
   "source": [
    "# 1.损失函数：cross_entropy\n",
    "cross_entropy = -tf.reduce_sum(y_ * tf.log(y_pre)) # y_ 中只有标签所在的那一类是 1， 其余全部都是0.\n",
    "# 2.优化函数：AdamOptimizer, 优化速度要比 GradientOptimizer 快很多\n",
    "train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)\n",
    "\n",
    "# 3.预测结果评估\n",
    "#　预测值中最大值（１）即分类结果，是否等于原始标签中的（１）的位置。argmax()取最大值所在的下标\n",
    "correct_prediction = tf.equal(tf.argmax(y_pre, 1), tf.arg_max(y_, 1))  \n",
    "accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n",
    "\n",
    "# 开始运行\n",
    "sess.run(tf.global_variables_initializer())\n",
    "# 这大概迭代了不到 10 个 epoch， 训练准确率已经达到了0.98\n",
    "for i in range(5000):\n",
    "    X_batch, y_batch = mnist.train.next_batch(batch_size=100)\n",
    "    train_step.run(feed_dict={X_: X_batch, y_: y_batch})\n",
    "    if (i+1) % 200 == 0:\n",
    "        train_accuracy = accuracy.eval(feed_dict={X_: mnist.train.images, y_: mnist.train.labels})\n",
    "        print \"step %d, training acc %g\" % (i+1, train_accuracy)\n",
    "    if (i+1) % 1000 == 0:\n",
    "        test_accuracy = accuracy.eval(feed_dict={X_: mnist.test.images, y_: mnist.test.labels})\n",
    "        print \"= \" * 10, \"step %d, testing acc %g\" % (i+1, test_accuracy)"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
